/**
 * Created By xiyuan
 * Author server@xiyuan.name (惜缘叛逆)
 * DateTime 2019/3/24 8:32 PM
 * Describe javascript功能描述
 * MIT License http://www.opensource.org/licenses/mit-license.php
 */

// 文件工具
const fs = require('fs');
// 路径包
const path = require('path');
// ini配置文件处理工具
const ini = require('ini');
// api处理工具
const {serverApi} = require('./apiTools')
// 配置转换
const {optionConvert} = require('./optionConvert');
// 进程管理
const {createProcess, getProcess} = require('./processMange');
// 工具集
const {dirExists} = require('./utils');

// 项目根目录
const projectDir = path.join(__dirname, '/../');

// 配置文件目录
const configDir = dirExists(path.normalize(projectDir + 'config/server/'));

// 日志目录
const logDir = dirExists(path.normalize(projectDir + 'log/server/'));

// 配置文件路径
const configPath = path.normalize(configDir + 'server.json');

// 国际化
const i18n = {
	zh: {
		"bind_addr": "绑定本地地址",
		"bind_port": "绑定本地端口",
		"bind_udp_port": "绑定udp端口",
		"kcp_bind_port": "绑定kcp端口",
		"vhost_http_port": "http站点端口",
		"vhost_https_port": "https站点端口",
		"dashboard_addr": "控制面板地址",
		"dashboard_port": "控制面板端口",
		"dashboard_user": "控制面板账号",
		"dashboard_pwd": "控制面板密码",
		"log_file": "日志文件路径",
		"log_level": "日志级别",
		"log_max_days": "日志保存天数",
		"token": "令牌",
		"allow_ports": "端口白名单",
		"max_pool_count": "最大连接数",
		"max_ports_per_client": "每个服务端最大端口",
		"subdomain_host": "主机子域名",
		"tcp_mux": "TCP多路复用"
	}
}

// 服务器公共配置规则
const commonRules = {
	"bind_addr": {
		value: "0.0.0.0",
		type: 'ip',
	},
	"bind_port": {
		type: 'port',
		value: "7000"
	},
	"bind_udp_port": {
		type: 'port',
	},
	"kcp_bind_port": {
		type: 'port',
	},
	"vhost_http_port": {
		type: 'port',
	},
	"vhost_https_port": {
		type: 'port',
	},
	"dashboard_addr": {
		type: 'ip',
	},
	"dashboard_port": {
		type: 'port',
	},
	// 管理用户名
	"dashboard_user": {
		type: 'text',
		value: "admin"
	},
	// 管理密码
	"dashboard_pwd": {
		type: 'text',
		value: "admin"
	},
	// 日志文件
	"log_file": {
		value: function (name) {
			return logDir + name + '.log'
		},
		type: 'path',
	},
	// 日志提示等级
	"log_level": {
		value: "info",
		type: "hidden"
	},
	// 日志保存天数
	"log_max_days": {
		type: "number",
		value: "3",
	},
	// 令牌标示
	"token": {
		type: 'text',
	},
	'allow_ports': {
		isRange: true,
		type: 'list_port',
	},
	// 日志保存天数
	"max_pool_count": {
		type: "number",
	},
	// 日志保存天数
	"max_ports_per_client": {
		type: "number",
	},
	"subdomain_host": {
		type: 'host'
	},
	// TCP 多路复用
	"tcp_mux": {
		value: true,
		type: 'switch',
	},
}

// 服务端公共数据
const serverData = {
	// 服务端容器
	container: [],
	// 累计服务端数量
	count: 0,
};

// 添加服务端
function addServer(server) {
	const {config, state} = readConfig();
	// 检查是否有同名服务
	const findIndex = state ? config.container.findIndex(info => info.name == server.name) : -1;
	if (findIndex !== -1) {
		serverData.count--;
		serverData.container.splice(findIndex, 1);
	}
	
	serverData.count++;
	serverData.container.push(server);
}

// 移除服务端
function removeServer(server) {

}

// 配置同步写入
function syncWriteConfig(targetserver, formatting) {
	// 读取配置
	const {config, state} = readConfig();
	const container = serverData.container.concat();
	// 数据合并
	if (state) {
		config.container.forEach(function (info) {
			if (!container.some(serverInfo => serverInfo.name == info.name)) {
				container.unshift(info);
			}
		})
	}
	
	// 写入保存所有服务端数据
	fs.writeFileSync(configPath, JSON.stringify({
		count: container.length,
		container: container
	}));
	// 检查是否要格式化对应服务端配置
	if (!formatting) return;
	const serverName = targetserver.name;
	// 进程配置路径
	const processconfigPath = configDir + serverName + '.ini';
	// 配置
	const serverConfig = {
		common: targetserver.common.configList[0]
	}
	// 保存并写入本地
	fs.writeFileSync(
		processconfigPath,
		ini.stringify(serverConfig)
	);
	return serverConfig;
}

// 配置读取
function readConfig() {
	let resString = '[]';
	// 捕获错误信息
	try {
		// 读取配置文件内容
		resString = fs.readFileSync(configPath, 'utf-8')
	}
	catch (e) {
		return {
			state: false,
			errMsg: e.message
		};
	}
	
	return {
		state: true,
		config: JSON.parse(resString)
	};
}


// 实例恢复
function serverRecover() {
	const {config, state} = readConfig();
	if (!state) return state;
	// 实例恢复
	config.container.map(config => {
		return new server(config);
	})
	
	return {
		start() {
			serverData.container.forEach(server => server.startProcess())
			return serverData.container;
		}
	}
}

// 服务端类
class server {
	constructor({name, common, logPath, options, isUse} = {},) {
		// 事件记录器
		this.eventMap = {
			start: [],
			info: [],
			error: [],
			close: [],
		};
		// 服务基础配置
		this.commConfig = {};
		// 服务端名称
		this.name = name || ('服务端' + serverData.count)
		// 是否启用
		this.isUse = isUse || false;
		// 公共配置
		this.common = common ? common : optionConvert('common', commonRules, options, this);
		// 配置列表
		const configList = this.common.configList;
		// 检查服务端端公共配置是否配置成功
		if (this.common.errMsg) {
			throw new Error(this.common.errMsg)
		} else {
			let config = this.commConfig = configList[configList.length - 1];
			// 日志路径
			this.logPath = config.log_file = logPath || config.log_file.split(path.sep).join('/');
		}
		// 存储服务端实例
		addServer(this);
	}
	
	// 启动代理连接
	start() {
		this.isUse = true;
		// 启动进程
		return this.startProcess();
	}
	
	// 关闭代理连接
	stop() {
		this.isUse = false;
		// 数据同步
		syncWriteConfig(this, true);
		// 关闭进程
		if (this.process) this.process.destroy();
	}
	
	// 启动进程
	startProcess() {
		// 数据同步
		syncWriteConfig(this, true);
		// 获取进程对象
		let process = getProcess('server', this);
		
		// 启动
		if (!process) {
			process = createProcess('server', this)
			// 输出监听
				.watchStart(info => {
					this.eventMap.start.forEach(fn => fn(this));
				})
				.watchInfo(info => {
					this.eventMap.info.forEach(fn => fn(info));
				})
				.watchError(info => {
					this.eventMap.error.forEach(fn => fn(info));
				})
				.watchClose(info => {
					this.eventMap.close.forEach(fn => fn(info));
					// 销毁进程对象
					delete this.process;
				})
			
		}
		
		// 检查进程是否启动
		if (process && !process.spawn) {
			process.start();
		}
		this.process = process;
		
		return this;
	}
	
	// 关闭进程
	closeProcess() {
		// 关闭进程
		if (this.process) this.process.destroy();
	}
	
	watchStart(fn) {
		if (this.process && this.process.isStart) {
			fn(this)
		} else {
			// 事件记录
			this.eventMap.start.push(fn);
		}
		return this;
	}
	
	// 监听信息输出
	watchInfo(fn) {
		// 事件记录
		this.eventMap.info.push(fn);
		return this;
	}
	
	// 监听错误输出
	watchError(fn) {
		// 事件记录
		this.eventMap.error.push(fn);
		return this;
	}
	
	// 监听进程关闭
	watchClose(fn) {
		// 事件记录
		this.eventMap.close.push(fn);
		return this;
	}
	
	// 接口处理
	api(Interface) {
		const commConfig = this.commConfig;
		// 接口处理
		return serverApi({
			interface: Interface,
			user: commConfig.user,
			pwd: commConfig.dashboard_user,
			host: commConfig.bind_addr,
			port: commConfig.dashboard_port,
		})
	}
	
}

module.exports = {
	// 国际化语言包
	i18n,
	// 服务端数据
	serverData,
	// 服务器公共配置规则
	commonRules,
	// 配置读取
	readConfig,
	// 实例恢复
	serverRecover,
	// 服务端创建
	createServer(...args) {
		return new server(...args);
	}
}